package com.shoparc.maidenlane;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Type;
import java.util.ArrayList;

import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;

import processing.core.PApplet;
import processing.core.PConstants;
import processing.core.PVector;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.shoparc.geo.Element;
import com.shoparc.geo.Polyline;
import com.shoparc.geo.Quad;
import com.shoparc.mvc.ViewFrame;

public class MaidenLane extends ViewFrame {

	ArrayList<FloorPlate> floorplates = new ArrayList<FloorPlate>();
	ArrayList<ArrayList<Vector3D>> workingPts = new ArrayList<ArrayList<Vector3D>>();
	ArrayList<ArrayList<PanelBrick>> panels = new ArrayList<ArrayList<PanelBrick>>();
	MLController mlc;

	/**
	 * 
	 */
	private static final long serialVersionUID = 2685293195086870127L;

	public void setup() {
		zoom = 300;
		super.setup();
		controller = new MLController(this);
		controller.setup();
		target = new PVector(-472, -2, 693);
		mlc = (MLController) controller;
		
		
		try {
			importFloorPlates();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		// createStaggeredWPts();
		//createStaggeredWPts(3, 8);
		createWorkingPts(15);
		// createRandomWPts();
		createPanel();
		//createBRKFrame();
		 createBRKStrFrame();
		// createStrtFrame();
		// setGlass();
	}

	public static void main(String args[]) {
		PApplet.main(new String[] { "--present",
				"com.shoparc.maidenlane.MaidenLane" });
	}

	public void draw() {

		beginCamera();
		strokeWeight(.125f);
		super.draw();
		stroke(0, 0, 0);
		fill(255, 255, 255);
		for (FloorPlate f : floorplates) {
			f.boundary.render(this);
		}

		beginShape(PConstants.LINES);
		for (ArrayList<Vector3D> wp : workingPts) {
			for (Vector3D v : wp) {
				// pushrenderPt(v, .5f);
			}
		}
		endShape();

		renderPanels();

		endCamera();
		beginCamera();

		camera();
		ortho();

		fill(0, 0, 0);

		textSize(10);
		text("zoom=" + zoom, 50, 50);
		text("lb=" + mlc.lowerB, 50, 70);
		text("ub=" + mlc.upperB, 50, 90);

		fill(255, 255, 255);

		endCamera();

	}

	public void importFloorPlates() throws IOException {

		String jsoninput = "";
		BufferedReader br = null;

		try {
			br = new BufferedReader(
					new FileReader(
							"C:/Users/cam/13workspace/EtySthStrt/input/130911_80ssInlines.txt"));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		try {
			StringBuilder sb = new StringBuilder();
			String line = br.readLine();

			while (line != null) {
				sb.append(line);
				sb.append("\n");
				line = br.readLine();
			}

			jsoninput = sb.toString();

		} finally {
			br.close();
		}

		ArrayList<Vector3D> testboundary = new ArrayList<Vector3D>();
		testboundary.add(new Vector3D(0, 0, 0));
		testboundary.add(new Vector3D(1, 1, 0));
		testboundary.add(new Vector3D(-2, 2, 0));
		ArrayList<Polyline> plines = new ArrayList<Polyline>();
		plines.add(new Polyline(testboundary));
		// plines.add(new Polyline(testboundary));

		Gson gson = new Gson();
		// print(jsoninput);
		// print(gson.toJson(plines));

		Type collectionType = new TypeToken<ArrayList<Polyline>>() {
		}.getType();
		// ArrayList<Polyline> ints2 = gson.fromJson(gson.toJson(plines),
		// collectionType);
		ArrayList<Polyline> unsortedLines = gson.fromJson(jsoninput,
				collectionType);
		ArrayList<Polyline> sortedInLines = new ArrayList<Polyline>();
		
		// sort the lines to make sure they are in the right order
		while (!unsortedLines.isEmpty()) {
			Polyline minPLine = unsortedLines.get(0);
			double minHt = minPLine.vertices.get(0).getZ();
			for (Polyline p : unsortedLines) {
				double currentHt = p.vertices.get(0).getZ();
				if (currentHt < minHt) { // a new min was found
					minHt = currentHt;
					minPLine = p;
				}
			}
			unsortedLines.remove(minPLine);
			sortedInLines.add(minPLine);
		}

		for (Polyline p : sortedInLines) {
			floorplates.add(new FloorPlate(p.vertices));

		}
	}

	public void createWorkingPts(double l) {

		for (FloorPlate f : floorplates) {

			workingPts.add(f.boundary.divideByLengthConstant(l));
			// workingPts.add(f.boundary.divideByLengthLazy(width+3));
			// workingPts.add(f.boundary.divideByLengthGrowing(0, 2,12));
		}

	}

	public void createStaggeredWPts() {
		double width = 3;
		// double x = Math.PI/2;
		double x = -4 * Math.PI / 8;
		for (int i = 0; i < floorplates.size(); i++) {
			width = 6 + Math.sin(x) * 3;
			x += 2 * Math.PI;
			if (width < 1) {
				width = 1;
			}
			while (width > 15) {
				width = 15;
			}
			// width = width%6;

			if (i % 2 == 0) {
				workingPts.add(floorplates.get(i).boundary
						.divideByLengthLazy(width));
				// workingPts.add(floorplates.get(i).boundary.divideByLengthLazy(15));
			} else {
				workingPts.add(floorplates.get(i).boundary.divideByLengthLazy(
						width, 2));
				// workingPts.add(floorplates.get(i).boundary.divideByLengthLazy(15,
				// 2));
			}
		}
	}

	public void createStaggeredWPts(int module, double width) {
		// width = 3;

		// double x = Math.PI/2;
		// double x = -4*Math.PI/8;
		for (int i = 0; i < floorplates.size(); i++) {
			/*
			 * width = 6+Math.sin(x)*3; x+=2*Math.PI/30; if(width<1){ width=1; }
			 * while(width>12){ width = 12; }
			 */

			
			  
			  double countModulo = i%module;
			  
			  
			  if(countModulo==0){
			  workingPts.add(floorplates.get(i).boundary.divideByLengthLazy
			  (width)); }else{ double offset = countModulo/module;
			  workingPts.add
			  (floorplates.get(i).boundary.divideByLengthLazy(width,
			  (offset))); } }
			 

			/*
			double countModulo = i % module;

			if (countModulo == 0) {
				
				
				workingPts.add(floorplates.get(i).boundary
						.divideByLengthGrowing(3, 3, 9, .75));
			} else {
				double offset = countModulo / module;
				workingPts.add(floorplates.get(i).boundary.divideByLengthLazy(
						width, (offset)));
			}
		}*/
	}

	public void createRandomWPts() {
		for (int i = 0; i < floorplates.size(); i++) {
			int myval = (int) Math.ceil((Math.random() * 5 + 3));
			workingPts.add(floorplates.get(i).boundary.divideByLengthLazy(
					myval, 2));

		}
	}

	public void createPanel() {
		double prevheight = workingPts.get(0).get(0).getZ();
		for (int i = 0; i < workingPts.size() - 1; i++) {

			ArrayList<Vector3D> wp = workingPts.get(i);
			int jmax = wp.size();
			ArrayList<PanelBrick> currentPanels = new ArrayList<PanelBrick>();

			for (int j = 0; j < jmax; j++) {

				Vector3D p1 = wp.get(j);
				Vector3D p2 = wp.get((j + 1) % jmax);
				double height = workingPts.get(i + 1).get(0).getZ();

				Vector3D p3 = new Vector3D(p2.getX(), p2.getY(), height);
				Vector3D p4 = new Vector3D(p1.getX(), p1.getY(), height);
				PanelBrick panel = new PanelBrick(p1, p2, p3, p4);

				currentPanels.add(panel);
			}

			panels.add(currentPanels);
		}
	}

	public void pushrenderPt(Vector3D v, float _scale) {
		float x = (float) v.getX();
		float y = (float) v.getY();
		float z = (float) v.getZ();
		vertex(x - _scale, y, z);
		vertex(x + _scale, y, z);
		vertex(x, y - _scale, z);
		vertex(x, y + _scale, z);
		vertex(x, y, z - _scale);
		vertex(x, y, z + _scale);
	}

	public void renderPanels() {
		stroke(100, 100, 100);

		fill(255, 255, 255);
		strokeWeight(.125f);
		// noStroke();
		beginShape(PApplet.QUADS);
		int i = 0;
		for (ArrayList<PanelBrick> somepanels : panels) {

			for (PanelBrick p : somepanels) {
				if ((i < mlc.lowerB) || (i > mlc.upperB)) {
					// p.renderPushVerts(this);
				}

				// p.glassPlane.renderPushVerts(this);

			}
			i++;
		}
		endShape();

		beginShape(PApplet.QUADS);
		fill(225, 225, 225);
		for (ArrayList<PanelBrick> somepanels : panels) {

			for (PanelBrick p : somepanels) {
				// p.renderPushVerts(this);
				// p.glassPlane.renderPushVerts(this);

				for (Quad q : p.frame) {

					q.pushVertices(this);

				}
			}

		}
		endShape();

	}

	public void createBRKFrame() {
		double angle = PI / 4;
		double angle2 = PI / 8;

		// double sx = 13.0/15, sy = 13.0/15, sz = 9.0/11;
		double sx = 5.0 / 13.5, sy = 5.0 / 13.5, sz = 8.5 / 11;
		double projection = 3.5;
		int count = 0;

		for (ArrayList<PanelBrick> somepanels : panels) {
			//if(Math.random()>.5){projection*=-1;}
			for (PanelBrick p : somepanels) {

				Vector3D norm = p.getNormal();
				norm = norm.scalarMultiply(projection);
				p.glassPlane.translate(norm);
				p.glassPlane.scale(sx, sy, sz);
				Vector3D axis2 = p.glassPlane.vertices.get(1).subtract(
						p.glassPlane.vertices.get(2));
				Rotation r = new Rotation(norm, angle);
				if (norm.getNorm() > 0) {

					if (projection <= 0) {
						//p.glassPlane.translate(new Vector3D(0, 0, 1));
						// p.glassPlane.scale(sx, sy, 1);
						// p.glassPlane.rotate(r);
						// Rotation r2 = new Rotation(axis2, angle2);
						//p.glassPlane.rotate(r2);

					}
					 projection*=-1;

					count++;

				}

				p.rotate(r);
				p.buildFrame();
				// p.buildFrameFlatFace();

			}
			// projection*=.98;
			// sx -= .004;
			// sy -= .004;
			// sz += .003;
			// angle -= Math.PI / 4 / 70;
			// angle2 -= Math.PI / 4 / 35;

		}
	}

	private void createBRKStrFrame() {
		double angle = PI / 4;
		double angle2 = PI / 8;

		// double sx = 13.0/15, sy = 13.0/15, sz = 9.0/11;
		double sx = 11.5 / 15, sy = 11.5 / 15, sz = 9.0 / 12;
		double projection = 0;
		int count = 0;

		for (ArrayList<PanelBrick> somepanels : panels) {
			// if(Math.random()>.5){projection*=-1;}
			for (PanelBrick p : somepanels) {

				Vector3D norm = p.getNormal();
				norm = norm.scalarMultiply(projection);
				p.glassPlane.translate(norm);
				p.glassPlane.scale(sx, sy, sz);
				Vector3D axis2 = p.glassPlane.vertices.get(1).subtract(
						p.glassPlane.vertices.get(2));
				if (norm.getNorm() > 0) {

					Rotation r = new Rotation(norm, angle);
					if (projection <= 0) {
						// p.glassPlane.translate(new Vector3D(0,0,1));
						// p.glassPlane.scale(sx, sy, 1);
						// p.glassPlane.rotate(r);
						// Rotation r2 = new Rotation(axis2, angle2);
						// p.glassPlane.rotate(r2);

					}
					//projection*=-1;

					count++;

				}

				// p.rotate(r);
				p.buildFrame();

				// p.buildFrameFlatFace();

			}

		}

	}

	public void createStrtFrame() {
		double angle = PI / 4;
		double angle2 = PI / 8;
		// double sx = 4.0/5, sy = 4.0/5, sz = 9.0/11;
		double sx = 4.75 / 5, sy = 4.75 / 5, sz = 9.5 / 11;
		double projection = -0;
		int count = 0;

		for (ArrayList<PanelBrick> somepanels : panels) {
			// if(Math.random()>.5){projection*=-1;}
			for (PanelBrick p : somepanels) {

				Vector3D norm = p.getNormal();
				norm = norm.scalarMultiply(projection);
				// p.glassPlane.translate(norm);
				p.glassPlane.scale(sx, sy, sz);
				Vector3D axis2 = p.glassPlane.vertices.get(1).subtract(
						p.glassPlane.vertices.get(2));
				if (norm.getNorm() > 0) {

					Rotation r = new Rotation(norm, angle);
					if (projection <= 0) {
						p.glassPlane.translate(new Vector3D(0, 0, 1));
						// p.glassPlane.scale(sx, sy, 1);
						// p.glassPlane.rotate(r);
						// Rotation r2 = new Rotation(axis2, angle2);
						// p.glassPlane.rotate(r2);

					}
					// projection*=-1;

					count++;

				}

				// p.rotate(r);
				// p.buildFrame();
				p.buildFrameFlatFace();

			}
			// projection*=.98;
			// sx -= .004;
			// sy -= .004;
			// sz += .003;
			// angle -= Math.PI / 4 / 70;
			// angle2 -= Math.PI / 4 / 35;

		}
	}

	public void setGlass() {

		/*
		 * double angle = 0; double angle2 = -PI/16; double sx = .9, sy=.9, sz =
		 * .6; double projection = (1.5f); for(ArrayList<PanelType1> somepanels
		 * : panels){
		 * 
		 * for(PanelType1 p : somepanels){ Vector3D norm = p.getNormal(); norm =
		 * norm.scalarMultiply(projection); p.glassPlane.translate(norm);
		 * p.glassPlane.scale(sx, sy, sz); Vector3D axis2 =
		 * p.glassPlane.vertices.get(0).subtract(p.glassPlane.vertices.get(2));
		 * if(norm.getNorm()>0){ Rotation r = new Rotation(norm, angle);
		 * p.glassPlane.rotate(r); Rotation r2 = new Rotation(axis2, angle2);
		 * p.glassPlane.rotate(r2);
		 * 
		 * }
		 * 
		 * //p.rotate(r); p.buildFrame();
		 * 
		 * }
		 * 
		 * sx-=.003; sy-=.003; sz+=.004; angle+=Math.PI/8/100;
		 * angle2+=Math.PI/16/100; }
		 */

		double angle = PI / 4;
		double angle2 = PI / 8;
		double sx = .65, sy = .65, sz = 6.0 / 11.0;
		double projection = -2;
		int count = 0;

		for (ArrayList<PanelBrick> somepanels : panels) {
			// if(Math.random()>.5){projection*=-1;}
			for (PanelBrick p : somepanels) {

				Vector3D norm = p.getNormal();
				norm = norm.scalarMultiply(projection);
				p.glassPlane.translate(norm);
				p.glassPlane.scale(sx, sy, sz);
				Vector3D axis2 = p.glassPlane.vertices.get(1).subtract(
						p.glassPlane.vertices.get(2));
				if (norm.getNorm() > 0) {

					Rotation r = new Rotation(norm, angle);
					if (projection <= 0) {
						p.glassPlane.translate(new Vector3D(0, 0, 1));
						// p.glassPlane.scale(sx, sy, 1);
						// p.glassPlane.rotate(r);
						// Rotation r2 = new Rotation(axis2, angle2);
						// p.glassPlane.rotate(r2);

					}
					// projection*=-1;

					count++;

				}

				// p.rotate(r);
				p.buildFrame();

			}
			// projection*=.98;
			// sx -= .004;
			// sy -= .004;
			// sz += .003;
			// angle -= Math.PI / 4 / 70;
			// angle2 -= Math.PI / 4 / 35;

		}

	}

	public void scaleGlass() {

	}

	public void exportAsText() {
		PrintWriter outFrame = null;
		PrintWriter outGlass = null;
		try {
			outFrame = new PrintWriter(
					"C:/Users/cam/13workspace/EtySthStrt/output/130709_OutFrame.txt");
			outGlass = new PrintWriter(
					"C:/Users/cam/13workspace/EtySthStrt/output/130709_OutGlass.txt");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		for (ArrayList<PanelBrick> somepanels : panels) {
			for (PanelBrick p : somepanels) {
				for (Quad q : p.frame) {

					outFrame.println(+q.vertices.get(0).getX() + ","
							+ q.vertices.get(0).getY() + ","
							+ q.vertices.get(0).getZ());
					outFrame.println(+q.vertices.get(1).getX() + ","
							+ q.vertices.get(1).getY() + ","
							+ q.vertices.get(1).getZ());
					outFrame.println(+q.vertices.get(2).getX() + ","
							+ q.vertices.get(2).getY() + ","
							+ q.vertices.get(2).getZ());
					outFrame.println(+q.vertices.get(3).getX() + ","
							+ q.vertices.get(3).getY() + ","
							+ q.vertices.get(3).getZ());
				}
				Element e = p.glassPlane;
				outGlass.println(e.vertices.get(0).getX() + ","
						+ e.vertices.get(0).getY() + ","
						+ e.vertices.get(0).getZ());
				outGlass.println(e.vertices.get(1).getX() + ","
						+ e.vertices.get(1).getY() + ","
						+ e.vertices.get(1).getZ());
				outGlass.println(e.vertices.get(2).getX() + ","
						+ e.vertices.get(2).getY() + ","
						+ e.vertices.get(2).getZ());
				outGlass.println(e.vertices.get(3).getX() + ","
						+ e.vertices.get(3).getY() + ","
						+ e.vertices.get(3).getZ());
			}
		}
		print("exported successfully");
	}

}
